package com.shuidihuzhu.sdb.helper.log.aspect;

import com.shuidihuzhu.sdb.helper.log.LogFur;
import com.shuidihuzhu.sdb.helper.log.utils.AnnotationUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.List;

/**
 * 切面
 */
@Slf4j
@Aspect
public class LogAspect {

    @Autowired(required = false)
    List<LogFur> logFurList;

    @Pointcut("@annotation(com.shuidihuzhu.sdb.helper.log.annotation.LogMethodInvoke) || @annotation(com.shuidihuzhu.sdb.helper.log.annotation.LogTrace)")
    public void doOperation() {
    }

    @Before("doOperation()")
    public void before(JoinPoint joinPoint) throws Throwable{
        if (CollectionUtils.isEmpty(logFurList)) {
            return;
        }

        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        for (LogFur logFur : logFurList) {
            final Class<Annotation> type = logFur.getType();
            final Annotation annotation = AnnotationUtil.getAnnotationFromTypeOrMethod(method, type);
            if (annotation != null) {
                try {
                    logFur.before(method, joinPoint.getArgs(), annotation);
                } catch (Throwable t) {
                    log.error("日志处理异常[@{} {}#{}]", type, method.getDeclaringClass().getName(), method.getName(), t);
                }
            }
        }
    }

    @AfterReturning(value = "doOperation()", returning = "result")
    public void doAfterReturning(JoinPoint joinPoint, Object result) {
        if (CollectionUtils.isEmpty(logFurList)) {
            return;
        }

        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        Method method = signature.getMethod();
        for (LogFur logFur : logFurList) {
            final Class<Annotation> type = logFur.getType();
            final Annotation annotation = AnnotationUtil.getAnnotationFromTypeOrMethod(method, type);
            if (annotation != null) {
                try {
                    logFur.after(method, result, annotation);
                } catch (Throwable t) {
                    log.error("日志处理异常", t);
                }
            }
        }
    }

    @AfterThrowing(value = "doOperation()", throwing = "error")
    public void afterThrowing(JoinPoint joinPoint, Throwable error) {
        System.out.println(joinPoint);
        error.printStackTrace();
    }
}
